home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Linux Cubed Series 7: Sunsite
/
Linux Cubed Series 7 - Sunsite Vol 1.iso
/
system
/
admin
/
linuxcon.000
/
linuxcon
/
linuxconf-1.6
/
netconf
/
hosts.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-07-25
|
11KB
|
512 lines
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <ctype.h>
#include <netdb.h>
#include "netconf.h"
#include "../misc/misc.h"
#include "../xconf/xconf.h"
#include "netconf.m"
static NETCONF_HELP_FILE help_hosts ("hosts");
NETCONF_HELP_FILE help_networks ("networks");
static CONFIG_FILE f_hosts (ETC_HOSTS,help_hosts,CONFIGF_MANAGED);
void *operator new(size_t size)
{
void *ret = malloc(size);
if (ret == NULL){
xconf_error (MSG_U(E_OUTOFMEMORY,"Out of memory\n"));
exit (-1);
}
return ret;
}
PUBLIC void HOST::set (const char *buf)
{
/* #Specification: /etc/hosts / format
A hosts file has the following format
# comment
ip_number hostname [ alias ... ] [ # comment ]
When we read /etc/hosts, we split the line in four parts, being
the ip_numer, the first name, all the alias and the comment.
Further, when collecting the comment, we try to keep even
the space between the last data and the #.
We hope to be able to edit normal /etc/hosts file and
rewrite it mostly respecting the original format.
Blank line are also remembered as comment.
*/
is_valid = 1;
freeall();
const char *pt = str_skip(buf);
if (isdigit(*pt)){
// First copy the ip number
char tmp[200];
char *ptd = tmp;
while (*pt > ' ') *ptd++ = *pt++;
*ptd = '\0';
ip_num.setfrom(tmp);
pt = str_skip (pt);
if (*pt > ' '){
ptd = tmp;
while (*pt > ' ') *ptd++ = *pt++;
*ptd = '\0';
name1.setfrom (tmp);
const char *endname1 = pt;
pt = str_skip (pt);
if (*pt == '#'){
comment.setfrom (endname1);
}else if (*pt > ' '){
const char *begother = pt;
while (*pt != '#' && *pt != '\0') pt++;
if (*pt == '\0'){
others.setfrom (begother);
}else{
while (isspace(pt[-1])) pt--;
int lenother = (int)(pt-begother);
memcpy (tmp,begother,lenother);
tmp[lenother] = '\0';
others.setfrom (tmp);
comment.setfrom (pt);
}
}
}else{
is_valid = 0;
}
}else if (*pt == '#'){
comment.setfrom (buf);
}else if (pt[0] != '\0'){
// Anything else than a blank link is an error at this point
is_valid = 0;
}
}
/*
Setup and parse a record from /etc/hosts
*/
PUBLIC HOST::HOST(const char *buf)
{
set (buf);
}
PUBLIC HOST::HOST(
const char *_ip_num,
const char *_name1,
const char *_others,
const char *_comment)
{
ip_num.setfrom (_ip_num);
name1.setfrom(_name1);
others.setfrom (_others);
comment.setfrom (_comment);
}
PUBLIC HOST::HOST()
{
}
/*
Cleanup of the HOST, same as destructor
*/
PRIVATE void HOST::freeall()
{
ip_num.setfrom (NULL);
name1.setfrom(NULL);
others.setfrom(NULL);
comment.setfrom(NULL);
}
PUBLIC VIRTUAL HOST::~HOST()
{
}
/*
Return the principal name of a host
*/
PUBLIC const char *HOST::getname1() const
{
return name1.get();
}
/*
Record the principal name of a host
*/
PUBLIC void HOST::setname1(const char *_name1)
{
name1.setfrom (_name1);
}
/*
Return != 0 if this entry is only a comment, not a host definition.
*/
PUBLIC int HOST::iscomment() const
{
return ip_num.is_empty();
}
/*
Return the comment associated with an entry.
*/
PUBLIC const char *HOST::getcomment() const
{
return comment.get();
}
/*
Record the comment associate with a host.
*/
PUBLIC void HOST::setcomment(const char *_comment)
{
comment.setfrom (_comment);
}
/*
Return the alternatives names for a host (maybe more than one) as
a single string or "" is none.
*/
PUBLIC const char *HOST::getothers() const
{
return others.get();
}
/*
Record the others names of a host
*/
PUBLIC void HOST::setothers(const char *_others)
{
others.setfrom (_others);
}
/*
Return the IP number of a host.
*/
PUBLIC const char *HOST::getipnum() const
{
return ip_num.get();
}
/*
Record the IP adress of a host.
*/
PUBLIC void HOST::setipnum(const char *_ipnum)
{
ip_num.setfrom (_ipnum);
}
/*
Output one HOST record in ascii
*/
PUBLIC VIRTUAL void HOST::print (FILE *fout) const
{
if (!ip_num.is_empty()) fprintf (fout,"%s",ip_num.get());
if (!name1.is_empty()) fprintf (fout,"\t%s",name1.get());
if (!others.is_empty()) fprintf (fout,"\t%s",others.get());
if (!comment.is_empty()) fprintf (fout,"%s",comment.get());
fputc ('\n',fout);
}
/*
Return !- 0 if this is a special entry of /etc/hosts.
This entry is special because it must exist for this program
to work (and many program). The loopback and the entry of the
current machine.
*/
PUBLIC VIRTUAL int HOST::is_special() const
{
return ip_num.is_empty()
|| ip_num.cmp("127.0.0.1")==0;
}
/*
Free and allocate conditionnally.
Return the new allocated pointer or NULL.
*/
char *replaceif(char *last,const char *newval)
{
free (last);
char *ret = NULL;
if (newval[0] != '\0') ret = strdup (newval);
return ret;
}
/*
Edit a host definition.
Return -1 if the input is cancelled
Return 0 if it is accepted
Return 1 if the user request deletion of this record.
*/
PUBLIC VIRTUAL int HOST::edit (HELP_FILE &helpfile)
{
int ret = -1;
DIALOG dia;
dia.newf_str (MSG_R(F_PRIMNAME),name1);
dia.newf_str (MSG_R(F_ALIASES),others);
dia.newf_str (MSG_U(F_IPNUM,"IP number"),ip_num);
dia.newf_str (MSG_R(F_COMMENT),comment);
int nofield = 0;
while (1){
int code = dia.edit (MSG_U(T_HOSTNETDEF,"host/network definition")
,NULL
,helpfile
,nofield,MENUBUT_CANCEL|MENUBUT_ACCEPT|MENUBUT_DEL);
if (code == MENU_CANCEL || code == MENU_ESCAPE){
break;
}else if (code == MENU_DEL){
ret = 1;
break;
}else if (code ==MENU_ACCEPT){
if (!device_validip(ip_num.get(),false)){
xconf_error (MSG_U(E_IVLIPNUM,"Invalid IP number"));
}else{
ret = 0;
break;
}
}
}
if (ret != 0) dia.restore();
return ret;
}
PUBLIC HOSTS::HOSTS()
{
cfgf = &f_hosts;
}
PUBLIC VIRTUAL HOST *HOSTS::newhost (
const char *_ip_num,
const char *_name1,
const char *_others,
const char *_comment)
{
return new HOST (_ip_num,_name1,_others,_comment);
}
PUBLIC VIRTUAL HOST *HOSTS::newhost (const char *buf)
{
return new HOST (buf);
}
/*
Add a line to the in memory hosts table
The line may be a comment or invalid
*/
PUBLIC VIRTUAL void HOSTS::add (const char *buf)
{
HOST *pt = newhost(buf);
add (pt);
}
/*
Add a line to the in memory hosts table
*/
PUBLIC VIRTUAL void HOSTS::add (
const char *_ip_num,
const char *_name1,
const char *_others,
const char *_comment)
{
HOST *pt = newhost (_ip_num,_name1,_others,_comment);
add (pt);
}
/*
Add one item to the in memory hosts table
*/
PUBLIC void HOSTS::add (HOST *pt)
{
grow();
tb[nb++] = pt;
}
/*
Read and parse a hosts file (normally /etc/hosts).
Return -1 if any error.
*/
PUBLIC int HOSTS::read ()
{
int ret = -1;
FILE *fin = cfgf->fopen ("r");
if (fin != NULL){
char buf[500];
ret = 0;
while (fgets_cont(buf,sizeof(buf)-1,fin) != -1){
add (buf);
}
fclose (fin);
}
return ret;
}
/*
Write a hosts file (normally /etc/hosts).
Return -1 if any error.
*/
PUBLIC int HOSTS::write () const
{
int ret = -1;
FILE *fout = cfgf->fopen ("w");
if (fout != NULL){
ret = 0;
for (int i=0; i<nb; i++) getitem(i)->print (fout);
fclose (fout);
}
return ret;
}
/*
Return one entry of the hosts file.
Returne NULL if the entry is out of range.
*/
PUBLIC HOST *HOSTS::getitem(int no) const
{
return (HOST*)ARRAY::getitem(no);
}
/*
Lookup a host name in the "other name" string.
Return != 0 if found.
*/
int host_lookupother (const char *others, const char *name)
{
int ret = 0;
while (1){
char buf[200];
others = str_skip(others);
others = str_copyword (buf,others);
if (buf[0] == '\0') break;
if (strcmp(buf,name)==0){
ret = 1;
break;
}
}
return ret;
}
/*
Find a name in the in memory host table.
Returne NULL or the entry.
*/
PUBLIC HOST *HOSTS::getitem(const char *name) const
{
HOST *ret = NULL;
if (name[0] != '\0'){
for (int i=0; i<nb; i++){
HOST *pt = getitem(i);
if (stricmp(name,pt->getname1())==0
|| host_lookupother(pt->getothers()
,name)){
ret = pt;
break;
}
}
}
return ret;
}
/*
Sort host by name
*/
static int cmp_host_by_name (const void *p1, const void *p2)
{
HOST *h1 = *(HOST**)p1;
HOST *h2 = *(HOST**)p2;
return strcmp(h1->getname1(),h2->getname1());
}
/*
Edit the file /etc/hosts or /etc/networks
*/
PUBLIC int HOSTS::edit(
const char *title,
HELP_FILE &helpfile)
{
int ret = -1;
int choice=0;
while (1){
int nbh = getnb(); // Number of entry including comments
HOST **tbsort = new HOST *[nbh];
if (tbsort != NULL){
// Extracting hosts only, no comments
// Hide information about this host
THISHOST thost;
const char *thishost_ip = thost.getipnum(0);
int nb=0;
for (int i=0; i<nbh; i++){
HOST *pt = getitem(i);
if (!pt->iscomment() && !pt->is_special()
&& strcmp(pt->getipnum(),thishost_ip)!=0){
tbsort[nb++] = pt;
}
}
qsort (tbsort,nb,sizeof(HOST *),cmp_host_by_name);
// Format all the entries in a menu.
// The first entry is dummy. It allows addition to the list
const char **menuopt = new const char *[(nb+2)*2+1];
int ii=0;
for (i=0; i<nb; i++,ii+=2){
HOST *pth = tbsort[i];
menuopt[ii] = (char*)pth->getipnum();
char buf[300];
sprintf (buf,"%s %s %s",pth->getname1(),pth->getothers()
,pth->getcomment());
buf[50] = '\0';
menuopt[ii+1] = strdup(buf);
}
menuopt[ii] = NULL;
//char save_what[100];
//sprintf (save_what,MSG_U(I_UPDHOSTS,"To update %s")
// ,cfgf->getpath());
MENU_STATUS code = xconf_menu (title
,MSG_U(I_HOSTSDEF
,"Select a host/network definition to modify")
,helpfile
,NULL
,NULL
,NULL
,MSG_U(I_ADDDEF,"to add a new definition")
,menuopt,choice);
if (code == MENU_ESCAPE || code == MENU_QUIT){
break;
}else if (code == MENU_ADD){
HOST *hst = newhost("");
if (hst != NULL){
if (hst->edit(helpfile)==0){
add(hst);
write ();
}else{
delete hst;
}
}
}else if(nb>0){
// Edit one hosts
HOST *hst = tbsort[choice];
int ok = hst->edit(helpfile);
if (ok != -1){
if (ok == 1) remove_del (hst);
write();
}
}
for (i=0; i<nb; i++) free ((char*)(menuopt[i*2+1]));
delete [] menuopt;
}
}
return ret;
}
/*
Edit the file /etc/hosts
*/
void netconf_edithosts()
{
HOSTS hosts;
if (hosts.read () != -1){
hosts.edit(ETC_HOSTS,help_hosts);
}
}
/*
Edit the file /etc/networks
*/
void netconf_editnet()
{
NETWORKS nets;
if (nets.read () != -1){
nets.edit(ETC_NETWORKS,help_networks);
}
}
#ifdef TEST
int main (int , char *[])
{
HOSTS hosts;
hosts.read ();
hosts.write ();
return 0;
}
#endif